﻿using Assets.XyzCode.Comm;
using Assets.XyzCode.Fight.Game.Enemy;
using Assets.XyzCode.VisualEffect;

using DragonBones;

using System;
using System.Collections;
using System.Collections.Generic;

using UnityEngine;

namespace Assets.XyzCode.Fight.Game.Player
{
    partial class Player_MissDie_Behav
    {
        /** 拳头输入 Cd, 也就是按键不能太快了 */
        private readonly CdTimer _punchInputCd = new CdTimer(0.2f);

        /** 当前拳头索引 */
        private int _currPunchIndex = 0;

        /** 拳头索引递增 Cd */
        private readonly CdTimer _punchIndexIncreaseCd = new CdTimer(0.64f);

        /** 存在命中 */
        private bool _existHit = false;

        /** 命中目标 Id 集合 */
        private readonly IDictionary<string, ISet<int>> _hitTargetIdDict = new Dictionary<string, ISet<int>>();

        /// <summary>
        /// 执行出拳
        /// </summary>
        /// <param name="dirX">X 轴上的移动方向, dirX &lt; 0 往左, dirX == 0 不动, dirX &gt; 0 往右</param>
        /// <param name="dirZ">Z 轴上的移动方向 ( 注意是 Z 轴不是 Y 轴 ), dirZ &lt; 0 往外, dirZ == 0 不动, dirZ &gt; 0 往里</param>
        public void DoPunch(int dirX, int dirZ)
        {
            if (!CanSwitchStateTo(StateEnum.Punch))
            {
                return;
            }

            _currState = StateEnum.Punch;
            _punchInputCd.Reset().Fill();

            if (_punchIndexIncreaseCd.IsHot() 
             && _existHit)
            {
                // 如果是连续出拳并且有命中,
                // 拳头索引 +1
                ++_currPunchIndex;
            }
            else
            {
                // 拳头索引归零
                _currPunchIndex = 0;
            }

            // 拳头索引发生变化, 
            // 清理存在命中标志
            _existHit = false;

            string eventName = "Punch_" + _currPunchIndex + "_Hit";

            if (_hitTargetIdDict.TryGetValue(eventName, out ISet<int> IdSet))
            {
                if (null == IdSet)
                {
                    IdSet = new HashSet<int>();
                    _hitTargetIdDict[eventName] = IdSet;
                }
                else
                {
                    IdSet.Clear();
                }
            }

            _punchIndexIncreaseCd.Reset().Fill();

            // 执行出拳移动
            StartCoroutine(PunchMove_XC(
                dirX, dirZ
            ));

            if (_currPunchIndex >= 4)
            {
                // 出拳 Cd 额外再增加一小段时间
                _punchInputCd.Extra(0.64f);
                PlayDBAnim("Punch_" + _currPunchIndex, 1);

                // 重置拳头索引
                _currPunchIndex = 0;
                _punchIndexIncreaseCd.Reset();

                transform.Find("PSys_0_").GetComponent<ParticleSystem>().Play();

                // 如果是 "升龙拳",
                // 那么会有一个震屏的效果...
                StartCoroutine(ShakeMainCamera_XC());
            }
            else
            {
                PlayDBAnim("Punch_" + _currPunchIndex, 1);
            }
        }

        /// <summary>
        /// 拳头命中
        /// </summary>
        /// <param name="eventName">事件名称</param>
        private void OnPunch_X_Hit(string eventName)
        {
            if (string.IsNullOrEmpty(eventName))
            {
                return;
            }

            // 获取敌人引用列表
            ICollection<WeakReference<GameObject>> goTargetRefColl = _attkableTargetDict.Values;

            if (goTargetRefColl.Count <= 0)
            {
                return;
            }

            foreach (WeakReference<GameObject> goTargetRef in goTargetRefColl)
            {
                if (null == goTargetRef)
                {
                    continue;
                }

                GameObject goCurrTarget;

                if (!goTargetRef.TryGetTarget(out goCurrTarget)
                 || null == goCurrTarget)
                {
                    // 如果目标为空,
                    // 或者已经已经命中该目标,
                    // 直接跳过...
                    continue;
                }

                if (_hitTargetIdDict.TryGetValue(eventName, out ISet<int> IdSet) 
                 && null != IdSet 
                 && IdSet.Contains(goCurrTarget.GetInstanceID()))
                {
                    continue;
                }

                if (null == IdSet)
                {
                    IdSet = new HashSet<int>();
                    _hitTargetIdDict[eventName] = IdSet;
                }

                IdSet.Add(goCurrTarget.GetInstanceID());
                _existHit = true;

                if ("Punch_4_Hit" == eventName)
                {
                    // 升龙拳命中
                    OnPunch_4_Hit(goCurrTarget);
                }
                else
                {
                    // 普通拳命中
                    OnPunch_0_Hit(goCurrTarget);
                }
            }
        }

        /// <summary>
        /// 普通拳命中
        /// </summary>
        /// <param name="goCurrTarget">当前目标对象</param>
        private void OnPunch_0_Hit(GameObject goCurrTarget)
        {
            if (null == goCurrTarget)
            {
                return;
            }

            // 命中之后创建光效
            GameObject goHitLit = HitLitFactory.Create();

            if (null != goHitLit)
            {
                goHitLit.transform.position = goCurrTarget.transform.position + Vector3.up * (1f + UnityEngine.Random.Range(0.2f, 1f));
            }

            int subtractHP = UnityEngine.Random.Range(-2, 2);
            subtractHP = 5 + subtractHP;

            // 执行受伤动作
            goCurrTarget.GetComponent<Enemy_X_Behav>()
                .SubtractHP(subtractHP)
                .DoWound(IsFaceToRight() ? 1 : -1);
        }

        /// <summary>
        /// 升龙拳命中
        /// </summary>
        /// <param name="goCurrTarget">当前目标对象</param>
        private void OnPunch_4_Hit(GameObject goCurrTarget)
        {
            if (null == goCurrTarget)
            {
                return;
            }

            // 命中之后创建光效
            GameObject goHitLit = HitLitFactory.Create();

            if (null != goHitLit)
            {
                goHitLit.transform.position = goCurrTarget.transform.position + Vector3.up * (1f + UnityEngine.Random.Range(0.2f, 1f));
            }

            // 计算减血量
            int subtractHP = UnityEngine.Random.Range(2, 5);
            subtractHP = 8 + subtractHP;

            // 方向角度
            float dirAngle;

            if (IsFaceToRight())
            {
                dirAngle = 70;
            }
            else
            {
                dirAngle = 110;
            }

            // 计算击飞角度和力度
            float angle = dirAngle + UnityEngine.Random.Range(-10, 10);
            float strength = UnityEngine.Random.Range(10, 15) + 3;

            goCurrTarget.GetComponent<Enemy_X_Behav>()
                .SubtractHP(subtractHP)
                .DoHitAway(dirAngle, strength);
        }

        /// <summary>
        /// ( 携程方式 ) 出拳移动
        /// </summary>
        /// <param name="dirX">X 轴上的移动方向</param>
        /// <param name="dirZ">Z 轴上的移动方向</param>
        /// <returns></returns>
        private IEnumerator PunchMove_XC(int dirX, int dirZ)
        {
            if (dirX < 0) { dirX = -1; } else if (dirX > 0) { dirX = 1; }
            if (dirZ < 0) { dirZ = -1; } else if (dirZ > 0) { dirZ = 1; }

            if (0 != dirX)
            {
                if (dirX > 0)
                {
                    transform.localRotation = FACE_TO_R;
                    _VIEW.GetComponent<UnityArmatureComponent>().armature.flipX = false;
                }
                else
                {
                    // 修改转向并修改 VIEW 的方向
                    transform.localRotation = FACE_TO_L;
                    _VIEW.GetComponent<UnityArmatureComponent>().armature.flipX = true;
                }
            }

            // 出拳移动是跑动速度的 N 倍,
            // XXX 但是注意: 每一帧过后会衰减...
            float speedX = RUN_SPEED_X;
            float speedZ = RUN_SPEED_Z;

            for (int i = 0; i < 256 && StateEnum.Punch == _currState; i++)
            {
                transform.position +=
                    Vector3.right * dirX * speedX * Time.deltaTime
                + Vector3.forward * dirZ * speedZ * Time.deltaTime;

                // 移动速度衰减
                speedX -= 10f * speedX * Time.deltaTime;
                speedZ -= 10f * speedZ * Time.deltaTime;

                yield return 1;
            }

            yield break;
        }

        /// <summary>
        /// ( 携程方式 ) 震动摄像机
        /// </summary>
        /// <returns>枚举迭代器</returns>
        private IEnumerator ShakeMainCamera_XC()
        {
            yield return new WaitForSeconds(0.2f);

            // XXX 注意: 震屏其实是控制摄像机移动
            // 
            float shockTime = 0.05f;
            const float AMPLITUDE = 3;

            while (shockTime > 0)
            {
                shockTime -= Time.deltaTime;
                Camera.main.transform.position += Vector3.up * AMPLITUDE * Time.deltaTime;
                yield return 1;
            }

            shockTime = 0.1f;

            while (shockTime > 0)
            {
                shockTime -= Time.deltaTime;
                Camera.main.transform.position += Vector3.down * AMPLITUDE * Time.deltaTime;
                yield return 1;
            }

            shockTime = 0.1f;

            while (shockTime > 0)
            {
                shockTime -= Time.deltaTime;
                Camera.main.transform.position += Vector3.up * AMPLITUDE * Time.deltaTime;
                yield return 1;
            }
        }
    }
}
